//----------------------------------------------------------------
#include "World.h"
//----------------------------------------------------------------
World::World(Renderer* pkRenderer)
:
m_pkRenderer(pkRenderer),
m_pkWorldMap(NULL)
{
	m_pkWorldMap = new Map(m_pkRenderer);

	// Representa los pesos del mapa, deberia tener relacion con el mapa de tiles cargado.
	// Los cambios en tiempo de ejecucion se dan en minas, bases y mineros, por lo tanto no afectan los pesos del mapa.
	int iMap [] = {
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0, 10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
	}; 
	m_pkPathfinder = new A(iMap, 25, 25);
}
//----------------------------------------------------------------
World::~World()
{
	if (m_pkWorldMap)
	{
		delete m_pkWorldMap;
		m_pkWorldMap = NULL;
	}

	while (!m_kGoldNodes.empty())
	{
		delete m_kGoldNodes.begin()->second;
		m_kGoldNodes.erase(m_kGoldNodes.begin());
	}
	while (!m_kStoneNodes.empty())
	{
		delete m_kStoneNodes.begin()->second;
		m_kStoneNodes.erase(m_kStoneNodes.begin());
	}
	while (!m_kWoodNodes.empty())
	{
		delete m_kWoodNodes.begin()->second;
		m_kWoodNodes.erase(m_kWoodNodes.begin());
	}
	while (!m_kFoodNodes.empty())
	{
		delete m_kFoodNodes.begin()->second;
		m_kFoodNodes.erase(m_kFoodNodes.begin());
	}
}
//----------------------------------------------------------------
bool World::addResourceNode(ResourceList kNodeType, int iPosX, int iPosY)
{
	if ( m_pkWorldMap->getTile(iPosX, iPosY, 1) != 0 )
	{
		#ifdef DEBUG_TEXT
		cout << "El lugar ya esta ocupado o fuera del mapa" << endl;
		#endif
		return false;
	}

	ResourceNode* kResource = new ResourceNode(kNodeType, MAX_AMOUNT_PER_NODE, iPosX, iPosY);
	pair<int, int> kPos;
	kPos.first = iPosX;
	kPos.second = iPosY;

	int iResourceTile;
	switch (kNodeType)
	{
		case ResourceList::Gold:
			iResourceTile = 4;
			m_kGoldNodes[kPos] = kResource;
			break;
		case ResourceList::Stone:
			iResourceTile = 6;
			m_kStoneNodes[kPos] = kResource;
			break;
		case ResourceList::Wood:
			iResourceTile = 7;
			m_kWoodNodes[kPos] = kResource;
			break;
		case ResourceList::Food:
			iResourceTile = 5;
			m_kFoodNodes[kPos] = kResource;
			break;
	}
	m_pkWorldMap->setTile(iPosX, iPosY, 1, iResourceTile);

	return true;
}
//----------------------------------------------------------------
bool World::removeResourceNode(ResourceList kNodeType, int iPosX, int iPosY)
{
	pair<int, int> kPos;
	kPos.first = iPosX;
	kPos.second = iPosY;

	ResourceNodeMapIterator itNode;

	switch (kNodeType)
	{
		case ResourceList::Gold:
			itNode = m_kGoldNodes.find(kPos);
			if ( itNode == m_kGoldNodes.end() )
				return false;
			else
				m_kGoldNodes.erase(itNode);
			break;
		case ResourceList::Stone:
			itNode = m_kStoneNodes.find(kPos);
			if ( itNode == m_kStoneNodes.end() )
				return false;
			else
				m_kStoneNodes.erase(itNode);
			break;
		case ResourceList::Wood:
			itNode = m_kWoodNodes.find(kPos);
			if ( itNode == m_kWoodNodes.end() )
				return false;
			else
				m_kWoodNodes.erase(itNode);
			break;
		case ResourceList::Food:
			itNode = m_kFoodNodes.find(kPos);
			if ( itNode == m_kFoodNodes.end() )
				return false;
			else
				m_kFoodNodes.erase(itNode);
			break;
	}

	m_pkWorldMap->setTile(iPosX, iPosY, 1, 0);

	return true;
}
//----------------------------------------------------------------
bool World::addPlayerBase(int iPosX, int iPosY)
{
	if ( (m_pkWorldMap->getTile(iPosX, iPosY, 1) != 0) )
	{
		#ifdef DEBUG_TEXT
		cout << "El lugar ya esta ocupado o fuera del mapa" << endl;
		#endif
		return false;
	}

	m_pkWorldMap->setTile(iPosX, iPosY, 1, 8);

	return true;
}
//----------------------------------------------------------------
bool World::loadWorldMap(const std::string& rkTileFile, const std::string& rkMapFile)
{
	if (!m_pkWorldMap->loadMap(rkTileFile, rkMapFile))
		return false;

	m_pkWorldMap->setPos(32,0);
	// Borro los tiles usados para los samples de los tiles que quiero usar en los nodos
	m_pkWorldMap->setTile(0,0,1,0);
	m_pkWorldMap->setTile(1,0,1,0);
	m_pkWorldMap->setTile(2,0,1,0);
	m_pkWorldMap->setTile(3,0,1,0);
	m_pkWorldMap->setTile(0,0,2,0);
	
	return true;
}
//----------------------------------------------------------------
void World::draw()
{
	m_pkWorldMap->draw();
}
//----------------------------------------------------------------
bool World::getNearestResourceNode(ResourceList kNodeType, vector<int>& rkPath, int iMinerPosX, int iMinerPosY, int& riNodePosX, int& riNodePosY)
{
	map<pair<int, int>, ResourceNode*> kNodeMap;
	switch (kNodeType)
	{
		case ResourceList::Gold:
			kNodeMap = m_kGoldNodes;
			break;
		case ResourceList::Stone:
			kNodeMap = m_kStoneNodes;
			break;
		case ResourceList::Wood:
			kNodeMap = m_kWoodNodes;
			break;
		case ResourceList::Food:
			kNodeMap = m_kFoodNodes;
			break;
	}

	if(kNodeMap.empty())
		return false;

	vector<int> kPath;
	int iDistance;
	int iMinDistance;
	bool bAtLeastOne = false;
	for (ResourceNodeMapIterator itNode = kNodeMap.begin(); itNode != kNodeMap.end(); itNode++)
	{
		if (m_pkPathfinder->calculatePath(itNode->second->getPosX(), itNode->second->getPosY(), iMinerPosX, iMinerPosY, kPath, iDistance))
		{
			if(itNode == kNodeMap.begin())
			{
				iMinDistance = iDistance;
				rkPath = kPath;
				riNodePosX = itNode->second->getPosX();
				riNodePosY = itNode->second->getPosY();
			}
			if(iDistance < iMinDistance)
			{
				iMinDistance = iDistance;
				rkPath = kPath;
				riNodePosX = itNode->second->getPosX();
				riNodePosY = itNode->second->getPosY();
			}
			bAtLeastOne = true;
		}
	}
	return bAtLeastOne;
}
//----------------------------------------------------------------
void World::getWorldPos(float& rfPosX, float& rfPosY)
{
	rfPosX = m_pkWorldMap->getPosX();
	rfPosY = m_pkWorldMap->getPosY();
}
//----------------------------------------------------------------
void World::getWorldData(int& riCols, int& riRows, int& riTileHeight, int& riTileWidth)
{
	riCols = m_pkWorldMap->getNumCols();
	riRows = m_pkWorldMap->getNumRows();
	riTileHeight = m_pkWorldMap->getTileHeight();
	riTileWidth = m_pkWorldMap->getTileWidth();
}
//----------------------------------------------------------------
void World::mineNode(ResourceList kNodeType, int iNodePosX, int iNodePosY, int& riAmountMined)
//AmountMined entra el maximo que puede llevar el minero, se setea con el minimo entre lo que entra, lo disponible en el nodo y lo maximo que se puede minar por vez
{
	map<pair<int, int>, ResourceNode*> kNodeMap;
	switch (kNodeType)
	{
		case ResourceList::Gold:
			kNodeMap = m_kGoldNodes;
			break;
		case ResourceList::Stone:
			kNodeMap = m_kStoneNodes;
			break;
		case ResourceList::Wood:
			kNodeMap = m_kWoodNodes;
			break;
		case ResourceList::Food:
			kNodeMap = m_kFoodNodes;
			break;
	}
	ResourceNodeMapIterator itNode = kNodeMap.find(pair<int,int>(iNodePosX, iNodePosY));
	if (itNode == kNodeMap.end())
	{
		riAmountMined = 0;
		return;
	}

	riAmountMined = min(itNode->second->getCurrentAmount(),min(riAmountMined, MAX_MINE_PER_TIME));
	itNode->second->mine(riAmountMined);

	if(itNode->second->getCurrentAmount() == 0)
		removeResourceNode(kNodeType, itNode->second->getPosX(), itNode->second->getPosY());
}
//----------------------------------------------------------------
